﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Reflection.Emit;

namespace DataTools.Memory
{

    [Flags]
    internal enum MemoryTypes
    {
        /// <summary>
        ///  Indicates that the memory pages within the region are mapped into the view of an image section.
        /// </summary>
        [Description(" Indicates that the memory pages within the region are mapped into the view of an image section.")]
        MEM_IMAGE = 0x1000000,

        /// <summary>
        ///  Indicates that the memory pages within the region are mapped into the view of a section.
        /// </summary>
        [Description(" Indicates that the memory pages within the region are mapped into the view of a section.")]
        MEM_MAPPED = 0x40000,

        /// <summary>
        ///  Indicates that the memory pages within the region are private (that is, not shared by other processes
        /// </summary>
        [Description(" Indicates that the memory pages within the region are private (that is, not shared by other processes")]
        MEM_PRIVATE = 0x20000

    }

    [Flags]
    internal enum MemoryStates
    {
        /// <summary>
        ///  Indicates committed pages for which physical storage has been allocated, either in memory or in the paging file on disk.
        /// </summary>
        [Description(" Indicates committed pages for which physical storage has been allocated, either in memory or in the paging file on disk.")]
        MEM_COMMIT = 0x1000,

        /// <summary>
        ///  Indicates free pages not accessible to the calling process and available to be allocated. For free pages, the information in the AllocationBase, AllocationProtect, Protect, and Type members is undefined.
        /// </summary>
        [Description(" Indicates free pages not accessible to the calling process and available to be allocated. For free pages, the information in the AllocationBase, AllocationProtect, Protect, and Type members is undefined.")]
        MEM_FREE = 0x10000,

        /// <summary>
        ///  Indicates reserved pages where a range of the process's virtual address space is reserved without any physical storage 
        /// </summary>
        [Description(" Indicates reserved pages where a range of the process's virtual address space is reserved without any physical storage ")]
        MEM_RESERVE = 0x2000

    }

    [Flags]
    internal enum MemoryProtectionFlags
    {
        /// <summary>
        /// Enables execute access to the committed region of pages. An attempt to read from or write to the committed region results in an access violation.
        /// </summary>
        [Description("Enables execute access to the committed region of pages. An attempt to read from or write to the committed region results in an access violation.")]
        PAGE_EXECUTE = 0x10,

        /// <summary>
        /// Enables execute or read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation.
        /// </summary>
        [Description("Enables execute or read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation.")]
        PAGE_EXECUTE_READ = 0x20,

        /// <summary>
        /// Enables execute, read-only, or read/write access to the committed region of pages.
        /// </summary>
        [Description("Enables execute, read-only, or read/write access to the committed region of pages.")]
        PAGE_EXECUTE_READWRITE = 0x40,

        /// <summary>
        /// Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. The private page is marked as PAGE_EXECUTE_READWRITE, and the change is written to the new page.
        /// </summary>
        [Description("Enables execute, read-only, or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. The private page is marked as PAGE_EXECUTE_READWRITE, and the change is written to the new page.")]
        PAGE_EXECUTE_WRITECOPY = 0x80,

        /// <summary>
        /// Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation.
        /// </summary>
        [Description("Disables all access to the committed region of pages. An attempt to read from, write to, or execute the committed region results in an access violation.")]
        PAGE_NOACCESS = 0x1,

        /// <summary>
        /// Enables read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation. If Data Execution Prevention is enabled, an attempt to execute code in the committed region results in an access violation.
        /// </summary>
        [Description("Enables read-only access to the committed region of pages. An attempt to write to the committed region results in an access violation. If Data Execution Prevention is enabled, an attempt to execute code in the committed region results in an access violation.")]
        PAGE_READONLY = 0x2,

        /// <summary>
        /// Enables read-only or read/write access to the committed region of pages. If Data Execution Prevention is enabled, attempting to execute code in the committed region results in an access violation.
        /// </summary>
        [Description("Enables read-only or read/write access to the committed region of pages. If Data Execution Prevention is enabled, attempting to execute code in the committed region results in an access violation.")]
        PAGE_READWRITE = 0x4,

        /// <summary>
        /// Enables read-only or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. The private page is marked as PAGE_READWRITE, and the change is written to the new page. If Data Execution Prevention is enabled, attempting to execute code in the committed region results in an access violation.
        /// </summary>
        [Description("Enables read-only or copy-on-write access to a mapped view of a file mapping object. An attempt to write to a committed copy-on-write page results in a private copy of the page being made for the process. The private page is marked as PAGE_READWRITE, and the change is written to the new page. If Data Execution Prevention is enabled, attempting to execute code in the committed region results in an access violation.")]
        PAGE_WRITECOPY = 0x8,

        /// <summary>
        /// Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm. For more information, see Creating Guard Pages.
        /// </summary>
        [Description("Pages in the region become guard pages. Any attempt to access a guard page causes the system to raise a STATUS_GUARD_PAGE_VIOLATION exception and turn off the guard page status. Guard pages thus act as a one-time access alarm. For more information, see Creating Guard Pages.")]
        PAGE_GUARD = 0x100,

        /// <summary>
        /// Sets all pages to be non-cachable. Applications should not use this attribute except when explicitly required for a device. Using the interlocked functions with memory that is mapped with SEC_NOCACHE can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.
        /// </summary>
        [Description("Sets all pages to be non-cachable. Applications should not use this attribute except when explicitly required for a device. Using the interlocked functions with memory that is mapped with SEC_NOCACHE can result in an EXCEPTION_ILLEGAL_INSTRUCTION exception.")]
        PAGE_NOCACHE = 0x200,

        /// <summary>
        /// Sets all pages to be write-combined.
        /// </summary>
        [Description("Sets all pages to be write-combined.")]
        PAGE_WRITECOMBINE = 0x400

    }

    [Flags]
    internal enum VMemFreeFlags
    {
        /// <summary>
        /// Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.
        /// The function does not fail if you attempt to decommit an uncommitted page. This means that you can decommit a range of pages without first determining the current commitment state.
        /// Do not use this value with MEM_RELEASE.
        /// </summary>
        /// <remarks></remarks>
        [Description("Decommits the specified region of committed pages. After the operation, the pages are in the reserved state.")]
        MEM_DECOMMIT = 0x4000,

        /// <summary>
        /// Releases the specified region of pages. After this operation, the pages are in the free state.
        /// </summary>
        /// <remarks></remarks>
        [Description("Releases the specified region of pages. After this operation, the pages are in the free state.")]
        MEM_RELEASE = 0x8000

    }

    [Flags]
    internal enum VMemAllocFlags
    {
        /// <summary>
        /// Allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved memory pages. The function also guarantees that when the caller later initially accesses the memory, the contents will be zero. Actual physical pages are not allocated unless/until the virtual addresses are actually accessed.
        /// </summary>
        [Description("Allocates memory charges (from the overall size of memory and the paging files on disk) for the specified reserved memory pages. The function also guarantees that when the caller later initially accesses the memory, the contents will be zero. Actual physical pages are not allocated unless/until the virtual addresses are actually accessed.")]
        MEM_COMMIT = 0x1000,

        /// <summary>
        /// Reserves a range of the process's virtual address space without allocating any actual physical storage in memory or in the paging file on disk.
        /// </summary>
        [Description("Reserves a range of the process's virtual address space without allocating any actual physical storage in memory or in the paging file on disk.")]
        MEM_RESERVE = 0x2000,

        /// <summary>
        /// Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages should not be read from or written to the paging file. However, the memory block will be used again later, so it should not be decommitted. This value cannot be used with any other value.
        /// </summary>
        [Description("Indicates that data in the memory range specified by lpAddress and dwSize is no longer of interest. The pages should not be read from or written to the paging file. However, the memory block will be used again later, so it should not be decommitted. This value cannot be used with any other value.")]
        MEM_RESET = 0x80000,

        /// <summary>
        /// MEM_RESET_UNDO should only be called on an address range to which MEM_RESET was successfully applied earlier. It indicates that the data in the specified memory range specified by lpAddress and dwSize is of interest to the caller and attempts to reverse the effects of MEM_RESET. If the function succeeds, that means all data in the specified address range is intact. If the function fails, at least some of the data in the address range has been replaced with zeroes.
        /// </summary>
        [Description("MEM_RESET_UNDO should only be called on an address range to which MEM_RESET was successfully applied earlier. It indicates that the data in the specified memory range specified by lpAddress and dwSize is of interest to the caller and attempts to reverse the effects of MEM_RESET. If the function succeeds, that means all data in the specified address range is intact. If the function fails, at least some of the data in the address range has been replaced with zeroes.")]
        MEM_RESET_UNDO = 0x1000000,

        /// <summary>
        /// Allocates memory using large page support. The size and alignment must be a multiple of the large-page minimum. To obtain this value, use the GetLargePageMinimum function.
        /// </summary>
        [Description("Allocates memory using large page support. The size and alignment must be a multiple of the large-page minimum. To obtain this value, use the GetLargePageMinimum function.")]
        MEM_LARGE_PAGES = 0x20000000,

        /// <summary>
        /// Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages.
        /// This value must be used with MEM_RESERVE and no other values.
        /// </summary>
        [Description("Reserves an address range that can be used to map Address Windowing Extensions (AWE) pages. This value must be used with MEM_RESERVE and no other values.")]
        MEM_PHYSICAL = 0x400000,

        /// <summary>
        /// Allocates memory at the highest possible address. This can be slower than regular allocations, especially when there are many allocations.
        /// </summary>
        [Description("Allocates memory at the highest possible address. This can be slower than regular allocations, especially when there are many allocations.")]
        MEM_TOP_DOWN = 0x100000,

        /// <summary>
        /// Causes the system to track pages that are written to in the allocated region. If you specify this value, you must also specify MEM_RESERVE.
        /// </summary>
        [Description("Causes the system to track pages that are written to in the allocated region. If you specify this value, you must also specify MEM_RESERVE.")]
        MEM_WRITE_WATCH = 0x200000

    }
        
    [StructLayout(LayoutKind.Sequential)]
    internal struct MEMORY_BASIC_INFORMATION
    {
        public IntPtr BaseAddress;
        public IntPtr AllocationBase;
        public MemoryProtectionFlags AllocationProtect;
        public IntPtr RegionSize;
        public MemoryStates State;
        public MemoryProtectionFlags Protect;
        public MemoryTypes Type;

    }

    public class Program
    {

        /// <summary>
        /// myStruct is not marshaled, directly.
        /// </summary>
        public struct myStruct
        {

            public int Length;
            public double[] Array;


            private IntPtr _ptr;

            /// <summary>
            /// Custom marshal a structure in from interop (and optionally free the original pointer).
            /// </summary>
            /// <param name="ptr"></param>
            /// <param name="freeOrig"></param>
            /// <returns></returns>
            public static myStruct MarshalIn(IntPtr ptr, bool freeOrig = true)
            {
                byte[] by = new byte[4];
                myStruct ns = new myStruct();

                Marshal.Copy(ptr, by, 0, 4);
                ns.Length = BitConverter.ToInt32(by, 0);

                ns.Array = new double[ns.Length];
                by = new byte[ns.Length * 8];

                Marshal.Copy(ptr + IntPtr.Size, by, 0, by.Length);
                Buffer.BlockCopy(by, 0, ns.Array, 0, by.Length);
                if (freeOrig) Marshal.FreeHGlobal(ptr);

                return ns;
            }

            /// <summary>
            /// Custom marshal a structure for calling interop.
            /// </summary>
            /// <returns></returns>
            public IntPtr MarshalOut()
            {
                IntPtr ptr;
                int l = IntPtr.Size + (8 * Array.Length);
                ptr = Marshal.AllocHGlobal(l);

                byte[] by = BitConverter.GetBytes(Length);

                Marshal.Copy(by, 0, ptr, 4);

                by = new byte[Length * 8];
                Buffer.BlockCopy(Array, 0, by, 0, by.Length);
                Marshal.Copy(by, 0, ptr + IntPtr.Size, by.Length);

                _ptr = ptr;
                return ptr;
            }

            /// <summary>
            /// Free any associated pointer with this structure created with MarshalOut().
            /// </summary>
            public void Free()
            {
                if (_ptr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(_ptr);
                    _ptr = IntPtr.Zero;
                }
            }
        }

        [DllImport("mylib.dll", SetLastError = true, CharSet = CharSet.None, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr doSomething(IntPtr inStruct, double val);


        
        static void Main()
        {

            myStruct ms = new myStruct(), ms2;
            ms.Array = new double[1];

            ms.Length = 1;
            ms.Array[0] = 424.444;

            ms2 = myStruct.MarshalIn(doSomething(ms.MarshalOut(), 524.444));

            // Free this if you know it should be.
            ms.Free();

        }
    
    
    }


    internal static class Interop
    {
        
        
        
        #region Allocation

        [DllImport("kernel32.dll")]
        public unsafe static extern void* HeapAlloc(void* hHeap, uint Flags, IntPtr size);

        [DllImport("kernel32.dll")]
        public unsafe static extern void* GetProcessHeap();

        [DllImport("kernel32.dll")]
        public unsafe static extern void* HeapReAlloc(void* hHeap, uint Flags, void* oldPtr, IntPtr newSize);

        [DllImport("kernel32.dll")]
        public unsafe static extern bool HeapFree(void* hHeap, uint Flags, void* ptr);

        [DllImport("kernel32.dll")]
        public unsafe static extern IntPtr HeapSize(void* hHeap, uint Flags, void* ptr);

        #endregion

        #region Virtual Allocation

        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]        
        public static unsafe extern void *VirtualAlloc(void *lpAddress, IntPtr dwSize, VMemAllocFlags flAllocationType, MemoryProtectionFlags flProtect);
        
        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static unsafe extern bool VirtualProtect(void* lpAddress, IntPtr dwSize, MemoryProtectionFlags flNewProtect, ref MemoryProtectionFlags flOldProtect);
        
        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static unsafe extern bool VirtualFree(void* lpAddress, IntPtr dwSize, VMemFreeFlags dwFreeType = VMemFreeFlags.MEM_RELEASE);
        
        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static unsafe extern IntPtr VirtualQuery(void* lpAddress, ref MEMORY_BASIC_INFORMATION lpBuffer, IntPtr dwLength);

        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static unsafe extern bool VirtualLock(void* lpAddress, IntPtr dwSize);

        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static unsafe extern bool VirtualUnlock(void* lpAddress, IntPtr dwSize);

        [DllImport("kernel32.dll", CharSet=CharSet.Unicode)]
        public static extern bool SetProcessWorkingSetSize(IntPtr hProcess, IntPtr dwMinimumWorkingSetSize, IntPtr dwMaximumWorkingSetSize);
        
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr GetLargePageMinimum();

        #endregion

        #region CopyMemory

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPWStr)] string src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPWStr)] string dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] byte[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] byte[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] sbyte[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] sbyte[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] char[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] char[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] short[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] short[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] ushort[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] ushort[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] int[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] int[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] uint[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] uint[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] long[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] long[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] ulong[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] ulong[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] float[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] float[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] double[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] double[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] decimal[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] decimal[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(IntPtr dest, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] Guid[] dest, IntPtr src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPWStr)] string src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPWStr)] string dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] byte[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] byte[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] sbyte[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] sbyte[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] char[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] char[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] short[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] short[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] ushort[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] ushort[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] int[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] int[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] uint[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] uint[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] long[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] long[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] ulong[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] ulong[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] float[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] float[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] double[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] double[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] decimal[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] decimal[] dest, void* src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory(void* dest, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] src, IntPtr length);

        [DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory")]
        public unsafe static extern void CopyMemory([Out, MarshalAs(UnmanagedType.LPArray)] Guid[] dest, void* src, IntPtr length);

        #endregion

        #region IL Emit MemCpy

        public unsafe delegate void MemCpyFunction(void* dest, void* src, uint byteLen);
        public unsafe static readonly MemCpyFunction MemCpy;

        static Interop()
        {
         
            unsafe
            {
                var dynamicMethod = new DynamicMethod
                 (
                     "MemCpy",
                     typeof(void),
                     new[] { typeof(void*), typeof(void*), typeof(uint) },
                     typeof(Interop)
                 );

                var ilGenerator = dynamicMethod.GetILGenerator();

                ilGenerator.Emit(OpCodes.Ldarg_0);
                ilGenerator.Emit(OpCodes.Ldarg_1);
                ilGenerator.Emit(OpCodes.Ldarg_2);

                ilGenerator.Emit(OpCodes.Unaligned);
                ilGenerator.Emit(OpCodes.Cpblk);
                ilGenerator.Emit(OpCodes.Ret);

                MemCpy = (MemCpyFunction)dynamicMethod.CreateDelegate(typeof(MemCpyFunction));
            }
        }

        #endregion


    }
}
